package org.dbstar.scheduler.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.StringBuilderWriter;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.dbstar.scheduler.beans.Catalog;
import org.dbstar.scheduler.beans.Job;
import org.dbstar.scheduler.beans.JobConf;
import org.dbstar.scheduler.beans.ParameterDefineType;
import org.dbstar.scheduler.control.CatalogController;
import org.dbstar.scheduler.control.JobConfController;
import org.dbstar.scheduler.control.JobController;
import org.dbstar.scheduler.control.exception.DaoException;
import org.dbstar.scheduler.identifier.Identifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;


/**
 * 用于页面EL表达式的辅助工具类
 * 
 * @author 代波
 * @since 1.0.0
 * @version 1.0.0
 * @date 2012-4-5
 */
public class Utils {
	private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);

	private static final AtomicLong today = new AtomicLong(0);

	public static String dateFormat(Long millis) {
		if (millis == null || millis == 0) {
			return "-";
		} else {
			long d = today.get();
			long now = System.currentTimeMillis();
			if (now - d >= 86400000) {
				try {
					d = new SimpleDateFormat("yyyy-MM-dd").parse(DateFormatUtils.format(now, "yyyy-MM-dd")).getTime();
					today.set(d);
				} catch (ParseException e) {
					today.set(now);
					d = now;
				}
			}
			if (millis.longValue() >= d && millis.longValue() < d + 86400000) {
				return DateFormatUtils.format(millis, "HH:mm:ss");
			} else {
				return DateFormatUtils.format(millis, "MM/dd HH:mm:ss");
			}
		}
	}

	public static String timeBetween(long end, long start) {
		if (start > 0 && end == 0) {
			return fromNowOn(start);
		} else if (start == 0 || end == 0) {
			return "-";
		} else if (start == -1 && end == -1) {
			return "-";
		}

		long mid = end - (start < 0 ? 0 : start);
		StringBuilder builder = new StringBuilder();
		if (mid >= 3600000) {
			builder.append(mid / 3600000).append(":");
			mid = mid % 3600000;
		}
		if (mid >= 60000) {
			long minute = mid / 60000;
			if (builder.length() > 0 && minute < 10) {
				builder.append("0");
			}
			builder.append(minute).append(":");
			mid = mid % 60000;
		} else if (builder.length() > 0) {
			builder.append("00:");
		}

		if (builder.length() > 0) {
			long sec = mid / 1000;
			if (sec < 10) {
				builder.append("0");
			}
			builder.append(sec);
		} else {
			builder.append(mid / 1000.0);
		}
		return builder.toString();
	}

	public static String fromNowOn(long millis) {
		return timeBetween(System.currentTimeMillis(), millis);
	}

	public static String showOutPut(InputStream in) {
		StringBuilderWriter writer = new StringBuilderWriter();
		showOutPut(in, writer);
		return writer.toString();
	}

	public static void showOutPut(InputStream in, Writer writer) {
		if (in != null) {
			BufferedReader reader = new BufferedReader(new InputStreamReader(in));
			try {
				writer.write("<pre>\n");
				String line;
				while ((line = reader.readLine()) != null) {
					int index = line.indexOf("\t");
					if (index >= 0) {
						long millis = Long.parseLong(line.substring(0, index));
						String msg = line.substring(index + 1);
						writer.write("<i>" + dateFormat(millis) + ":</i> " + msg + "\n");
					} else {
						writer.write("<i>:</i> " + line + "\n");
					}
				}
				writer.write("</pre>\n");
			} catch (IOException e) {
				LOGGER.error("读取Job结果的错误输出流时发生异常。", e);
			}
			IOUtils.closeQuietly(reader);
		}
	}

	public static String showOutPut(InputStream stdOut, InputStream errOut) {
		StringBuilderWriter writer = new StringBuilderWriter();
		showOutPut(stdOut, errOut, writer);
		return writer.toString();
	}

	public static void showOutPut(InputStream stdOut, InputStream errOut, Writer writer) {
		boolean hasStdOut = stdOut != null;
		boolean hasErrOut = errOut != null;

		BufferedReader std = hasStdOut ? new BufferedReader(new InputStreamReader(stdOut)) : null;
		BufferedReader err = hasErrOut ? new BufferedReader(new InputStreamReader(errOut)) : null;
		if (hasStdOut || hasErrOut) {
			try {
				writer.write("<pre>\n");
				TimeMessage stdMsg = new TimeMessage(std, true);
				TimeMessage errMsg = new TimeMessage(err, false);
				while (!stdMsg.isNull() || !errMsg.isNull()) {
					if (stdMsg.isNull()) {
						showOutPut(writer, errMsg);
						errMsg = new TimeMessage(err, false);
					} else if (errMsg.isNull()) {
						showOutPut(writer, stdMsg);
						stdMsg = new TimeMessage(std, true);
					} else {
						if (errMsg.millis < stdMsg.millis) {
							showOutPut(writer, errMsg);
							errMsg = new TimeMessage(err, false);
						} else {
							showOutPut(writer, stdMsg);
							stdMsg = new TimeMessage(std, true);
						}
					}
				}
				writer.write("</pre>\n");
			} catch (IOException e) {
				LOGGER.error("读取Job结果的错误输出流时发生异常。", e);
			}
			IOUtils.closeQuietly(std);
			IOUtils.closeQuietly(err);
		}
	}

	private static void showOutPut(Writer writer, TimeMessage msg) throws IOException {
		StringBuilder builder = new StringBuilder();
		builder.append("<span class='").append(msg.std ? "std" : "err").append("'>");
		builder.append("<i>");
		if (msg.millis > 0) {
			builder.append(dateFormat(msg.millis)).append(' ');
		}
		builder.append(msg.std ? "std" : "err").append("&nbsp;-&nbsp;</i>");
		builder.append(msg.msg).append("</span>\n");
		writer.write(builder.toString());
	}

	private static class TimeMessage {
		public long millis;
		public String msg;
		public boolean std;

		public TimeMessage(BufferedReader reader, boolean std) throws IOException {
			if (reader != null) {
				String log = reader.readLine();
				if (log != null) {
					int index = log.indexOf("\t");
					if (index >= 0) {
						this.millis = Long.parseLong(log.substring(0, index));
						setMsg(log.substring(index + 1));
					} else {
						setMsg(log);
					}
					this.std = std;
				}
			}
		}

		private void setMsg(String msg) {
			this.msg = msg.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
		}

		public boolean isNull() {
			return this.msg == null;
		}
	}

	public static String getParameterDefineTypeName(ParameterDefineType type) {
		switch (type) {
		case none:
			return "无预设值";
		case pre:
			return "缺省值";
		case now:
			return "当前时间";
		case lastMinute:
			return "前一分钟";
		case lastHour:
			return "前一小时";
		case lastDay:
			return "前一日";
		case lastWeek:
			return "前一周";
		case lastMonth:
			return "前一月";
		case lastYear:
			return "前一年";
		default:
			return type.name();
		}
	}

	public static List<Catalog> getAllCatalogs(CatalogController controller) throws DaoException {
		return getAllCatalogs(controller, new LinkedList<Catalog>(), controller.getRootCatalog());
	}

	private static List<Catalog> getAllCatalogs(CatalogController controller, List<Catalog> list, Catalog catalog)
			throws DaoException {
		list.add(catalog);
		for (Catalog c : controller.getSubCatalogs(catalog.getId())) {
			getAllCatalogs(controller, list, c);
		}
		return list;
	}

	public static int getCatalogDeep(CatalogController controller, Catalog catalog) throws DaoException {
		int deep = 0;
		while (catalog.getParent() != null) {
			catalog = controller.getCatalog(catalog.getParent());
			deep++;
		}
		return deep;
	}

	public static String getCatalogDeepName(CatalogController controller, Catalog catalog) throws DaoException {
		int deep = getCatalogDeep(controller, catalog);
		StringBuilder builder = new StringBuilder();
		if (deep > 0) {
			builder.append(StringUtils.repeat("&nbsp;&nbsp;&nbsp;&nbsp;", deep));
		}
		builder.append(catalog.getName());
		return builder.toString();
	}

	public static String getCatalogName(CatalogController controller, int cid) throws DaoException {
		Catalog catalog = controller.getCatalog(cid);
		return catalog == null ? "" : catalog.getName();
	}

	public static JobConf getJobConf(JobConfController controller, Identifier identifier) throws DaoException {
		return controller.getJobConf(identifier);
	}

	public static Job getJob(JobController controller, Identifier identifier) throws DaoException {
		return controller.getJob(identifier);
	}

	public static String getJobLabel(Job job, int index) {
		if (job.getParameterSize() > 0) {
			String label = job.getParameters().get("${hour}");
			if (label == null) {
				label = job.getParameters().get("${day}");
			}
			if (label == null) {
				label = job.getParameters().get("${date}");
			}
			if (label == null) {
				label = job.getParameters().get("${logDate}");
			}
			if (label == null) {
				label = job.getParameters().get("${toDate}");
			}
			if (label != null) {
				return label.length() > 2 ? label.substring(label.length() - 2) : label;
			}
		}
		return String.valueOf(index);
	}

	public static String getMapValue(Map<String, String> map, String key) {
		return map == null ? null : map.get(key);
	}

	public static String getServerPath(HttpServletRequest request) {
		return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
				+ request.getContextPath();
	}

	public static String getItemImage(int itemId) {
		int server = 1 + (itemId % 4);
		String code = String.valueOf(itemId);
		if (code.length() < 9) {
			code = StringUtils.repeat("0", 9 - code.length()) + code;
		}
		code = code.substring(0, 3) + '/' + code.substring(3, 6) + '/' + code.substring(6, 9);
		return "http://i" + server + ".tdimg.com/" + code + "/p.jpg";
	}

	public static String getItemName(int itemId, JdbcTemplate jt) {
		return jt.query("select title from Item where itemid=" + itemId, new ResultSetExtractor<String>() {
			@Override
			public String extractData(ResultSet rs) throws SQLException, DataAccessException {
				if (rs.next()) {
					return rs.getString("title");
				} else {
					return null;
				}
			}
		});
	}
}
